/*
 * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "securec.h"
#include "bootevent.h"
#include <gtest/gtest.h>
#include "init_utils.h"
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sys/mount.h>
#include <unistd.h>

#define BOOTEVENT_LEN 4
using namespace std;
using namespace testing::ext;
namespace init_ut {
const char* g_bootEventOta1[] = {"bootEvent1", "bootEvent3"};
const char* g_bootEventOta2[] = {"bootEvent1", "bootEvent4"};
const char* g_bootEventOta3[] = {"bootEvent2", "bootEvent3"};
const char* g_bootEventOta4[] = {"bootEvent2", "bootEvent4"};

// Define the possible return values for OTA status
enum ReturnSetOtaStatus {
    SET_OTA_STATUS_FAILED = -1, // Failed to call SetOTAStatus to set information.
    BOOT_SUCCESS_IN_OTA = 0,    // In the ota stage, startup is complete.
    BOOT_SUCCESS_IN_NORMAL = 1, // In the non-ota stage, startup is complete.
    BOOT_FAILD_IN_OTA = 2,      // In the ota stage, startup is failed.
    BOOT_FAILD_IN_NORMAL = 3,   // In the non-ota stage, startup is failed.
};

void SystemReadParam(const char* param, char* value, uint32_t* len)
{
    if (strcmp(param, "bootEvent1") == 0 || strcmp(param, "bootEvent3") == 0) {
        int ret = strncpy_s(value, *len, "true", strlen("true"));
        if (ret != 0) {
            printf("strncpy_s failed\n");
        }
    } else if (strcmp(param, "bootEvent2") == 0 || strcmp(param, "bootEvent4") == 0) {
        int ret = strncpy_s(value, *len, "false", strlen("false"));
        if (ret != 0) {
            printf("strncpy_s failed\n");
        }
    } else {
        int ret = strncpy_s(value, *len, "unknown", strlen("unknown"));
        if (ret != 0) {
            printf("strncpy_s failed\n");
        }
    }
}
static int BootEventJudgeBootComplete1(void)
{
    char value[6] = "";
    uint32_t len = sizeof(value);
    int booteventLength = sizeof(g_bootEventOta1) / sizeof(g_bootEventOta1[0]);
    
    for (int i = 0; i < booteventLength; i++) {
        SystemReadParam(g_bootEventOta1[i], value, &len);
        if (strncmp(value, "true", BOOTEVENT_LEN) != 0) {
            return 0;
        }
    }
    return 1;
}
static int BootEventJudgeBootComplete2(void)
{
    char value[6] = "";
    uint32_t len = sizeof(value);
    int booteventLength = sizeof(g_bootEventOta2) / sizeof(g_bootEventOta2[0]);
    
    for (int i = 0; i < booteventLength; i++) {
        SystemReadParam(g_bootEventOta2[i], value, &len);
        if (strncmp(value, "true", BOOTEVENT_LEN) != 0) {
            return 0;
        }
    }
    return 1;
}
static int BootEventJudgeBootComplete3(void)
{
    char value[6] = "";
    uint32_t len = sizeof(value);
    int booteventLength = sizeof(g_bootEventOta3) / sizeof(g_bootEventOta3[0]);
    
    for (int i = 0; i < booteventLength; i++) {
        SystemReadParam(g_bootEventOta3[i], value, &len);
        if (strncmp(value, "true", BOOTEVENT_LEN) != 0) {
            return 0;
        }
    }
    return 1;
}

static int BootEventJudgeBootComplete4(void)
{
    char value[6] = "";
    uint32_t len = sizeof(value);
    int booteventLength = sizeof(g_bootEventOta4) / sizeof(g_bootEventOta4[0]);
    
    for (int i = 0; i < booteventLength; i++) {
        SystemReadParam(g_bootEventOta4[i], value, &len);
        if (strncmp(value, "true", BOOTEVENT_LEN) != 0) {
            return 0;
        }
    }
    return 1;
}
void RebootSystem()
{
    printf("System is rebooting...\n");
}
int Mount(const char *source, const char *target, const char *filesystemtype,
          unsigned long mountflags, const void *data)
{
    return 0; // Simulate successful mount
}
static int HandleBootStatus(int retOta)
{
    switch (retOta) {
        case BOOT_SUCCESS_IN_OTA:
            {
                const char *mountPoint = "/data";
                const char *fsType = "f2fs";
                const char *options = "checkpoint=enable";
                int result = Mount(mountPoint, mountPoint, fsType, MS_REMOUNT, options);
                if (result != 0) {
                    return -1;
                }
                printf("boot success in normal, no process.\n");
                break;
            }

        case BOOT_SUCCESS_IN_NORMAL:
            printf("boot success in normal, no process.\n");
            break;

        case BOOT_FAILD_IN_OTA:
            printf("boot faild in OTA, start to reboot.\n");
            RebootSystem();
            break;

        case BOOT_FAILD_IN_NORMAL:
            printf("boot faild in normal, no process.\n");
            break;

        case SET_OTA_STATUS_FAILED:
            printf("Set OTA status failed, no process.\n");
            break;

        default:
            printf("Unknown boot status, no process.\n");
            break;
    }
    return 1;
}
class OtaRollbackUnitTest : public testing::Test {
public:
    static void SetUpTestCase(void)
    {
        cout << "OTA Rollback Unittest Begin!" << endl;
    };
    static void TearDownTestCase(void)
    {
        cout << "OTA Rollback Unittest End!" << endl;
    };
    void SetUp(void) {};
    void TearDown(void) {};
};
HWTEST_F(OtaRollbackUnitTest, BootEventJudgeBootComplete_001, TestSize.Level0)
{
    int result1 = BootEventJudgeBootComplete1();
    EXPECT_EQ(result1, 1);

    int result2 = BootEventJudgeBootComplete2();
    EXPECT_EQ(result2, 0);

    int result3 = BootEventJudgeBootComplete3();
    EXPECT_EQ(result3, 0);

    int result4 = BootEventJudgeBootComplete4();
    EXPECT_EQ(result4, 0);
}

HWTEST_F(OtaRollbackUnitTest, Init_OtaRollback_001, TestSize.Level0)
{
    int result1 = HandleBootStatus(BOOT_SUCCESS_IN_OTA);
    EXPECT_EQ(result1, 1);

    int result2 = HandleBootStatus(BOOT_SUCCESS_IN_NORMAL);
    EXPECT_EQ(result2, 1);

    int result3 = HandleBootStatus(BOOT_FAILD_IN_OTA);
    EXPECT_EQ(result3, 1);

    int result4 = HandleBootStatus(BOOT_FAILD_IN_NORMAL);
    EXPECT_EQ(result4, 1);

    int result5 = HandleBootStatus(SET_OTA_STATUS_FAILED);
    EXPECT_EQ(result5, 1);

    int result6 = HandleBootStatus(999);
    EXPECT_EQ(result6, 1);

    int  result7 = HandleBootStatus(-1);
    EXPECT_EQ(result7, 1);
}
}
